import 'dart:async';
import 'dart:io';

import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';

import 'api_server.dart';
import 'config.dart';
import 'interceptor.dart';

enum HttpMethod {
  get,
  post,
  put,
  delete,
}

class HTTPUtil {
  static HTTPUtil _instance = HTTPUtil._internal();

  static HTTPUtil get instance => _instance;

  Dio dio = Dio();
  CancelToken _cancelToken = CancelToken();

  HTTPUtil._internal() {
    // BaseOptions、Options、RequestOptions 都可以配置参数，优先级别依次递增，且可以根据优先级别覆盖参数
    dio.options = BaseOptions(
      // 连接超时
      connectTimeout: NetConfig.connectTimeout,
      //发送超时
      sendTimeout: NetConfig.sendTimeout,
      // 响应流上前后两次接受到数据的间隔，单位为毫秒。
      receiveTimeout: NetConfig.receiveTimeout,
      // Http请求头.tod o
      /*headers: {
        // NetConfig.headerContentType: NetConfig.contentTypeForm,
        'Authorization': token,
      },*/
    );

    // 添加异常拦截器
    dio.interceptors.add(ErrorInterceptor());
    dio.interceptors.add(ResponseInterceptor());
    // dio.interceptors.add(LoadingInterceptor());
    // 添加日志拦截器
    if (!kReleaseMode)
      dio.interceptors.add(LogInterceptor(
        requestBody: true,
        responseBody: true,
      ));

    // 在调试模式下需要抓包调试，所以我们使用代理，并禁用HTTPS证书校验
    if (NetConfig.proxyEnable) {
      (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
          (client) {
        client.findProxy = (uri) {
          return "PROXY ${NetConfig.proxyIp}:${NetConfig.proxyPort}";
        };
        //代理工具会提供一个抓包的自签名证书，会通不过证书校验，所以我们禁用证书校验
        client.badCertificateCallback =
            (X509Certificate cert, String host, int port) => true;
      };
    }
  }

  ///初始化公共属性
  ///
  /// [baseUrl] 地址前缀
  /// [proxyEnable] 是否开启代理
  /// [proxyIp] 代理ip
  /// [proxyPort] 代理端口
  Future<void> config({
    /*required*/ String baseUrl = 'https://iesapi.acadsoc.com.cn/',
    int? connectTimeout = NetConfig.connectTimeout,
    int? sendTimeout = NetConfig.sendTimeout,
    int? receiveTimeout = NetConfig.receiveTimeout,
    List<Interceptor>? interceptors,
    bool proxyEnable = false,
    String proxyIp = '192.168.2.237',
    String proxyPort = '8888',
  }) async {
    //初始化默认参数
    dio.options.baseUrl = baseUrl;
    dio.options.connectTimeout = connectTimeout ?? NetConfig.connectTimeout;
    dio.options.sendTimeout = connectTimeout ?? NetConfig.sendTimeout;
    dio.options.receiveTimeout = receiveTimeout ?? NetConfig.receiveTimeout;

    if (interceptors != null && interceptors.isNotEmpty) {
      dio.interceptors.addAll(interceptors);
    }

    //处理代理
    NetConfig.proxyEnable = proxyEnable;
    NetConfig.proxyIp = proxyIp;
    NetConfig.proxyPort = proxyPort;

    addHeaders({
      'Authorization': await HostHttp.instance.token(),
    });
  }

  ///默认post
  ///
  ///[onSuccess] default is Map
  ///
  /// [onFail] code 非空
  ///
  ///加before，end
  Future<void> req(String path,
      {data,
      Map<String, dynamic>? queryParameters,
      Options? options,
      CancelToken? cancelToken,
      HttpMethod method = HttpMethod.post,
      onSuccess(dynamic? data)?,
      onFail({String? msg, int? code})?}) async {
    var response;
    try {
      response = await _request(
        path,
        data: data,
        queryParameters: queryParameters,
        options: options,
        cancelToken: cancelToken ?? _cancelToken,
        method: method,
      );

      if (response != null) {
        if (response.ok) {
          onSuccess?.call(response.data);
        } else
          onFail?.call(code: response.code, msg: response.msg);
      }
    } on DioError catch (e) {
      // The request was made and the server responded with a status code
      // that falls out of the range of 2xx and is also not 304.
      if (e.response != null) {
      } else {
        // Something happened in setting up or sending the request that triggered an Error
      }
      if (CancelToken.isCancel(e)) {}
      onFail?.call(code: e.error.code, msg: e.error.msg);
    }
  }

  Future _request(
    String path, {
    required HttpMethod method,
    data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
  }) async {
    //处理请求方法
    if (method == HttpMethod.get) {
      dio.options.method = 'GET';
    } else if (method == HttpMethod.post) {
      dio.options.method = 'POST';
    } else if (method == HttpMethod.delete) {
      dio.options.method = 'DELETE';
    } else if (method == HttpMethod.put) {
      dio.options.method = 'PUT';
    }
    //处理请求设置
    options = options ?? Options();
    var res = await dio.request(
      path,
      data: data,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken ?? _cancelToken,
      onSendProgress: onSendProgress,
      onReceiveProgress: onReceiveProgress,
    );

    return res.data;
  }

  /*Future<BaseResponse<T>> _requestI<T>(
    String path, {
    required HttpMethod method,
    data,
    Map<String, dynamic>? queryParameters,
    Options? options,
    CancelToken? cancelToken,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
  }) async {
    //处理请求方法
    if (method == HttpMethod.get) {
      dio.options.method = 'GET';
    } else if (method == HttpMethod.post) {
      dio.options.method = 'POST';
    } else if (method == HttpMethod.delete) {
      dio.options.method = 'DELETE';
    } else if (method == HttpMethod.put) {
      dio.options.method = 'PUT';
    }
    //处理请求设置
    options = options ?? Options();
    Completer<BaseResponse<T>> completer = Completer();
    dio
        .request(
          path,
          data: data,
          queryParameters: queryParameters,
          options: options,
          cancelToken: cancelToken ?? _cancelToken,
          onSendProgress: onSendProgress,
          onReceiveProgress: onReceiveProgress,
        )
        .then((value) => {
              */ /*compute(BaseResponse.fromJso, value.data as Map<String, dynamic>)
                  .then(
                      (value) => completer.complete(value as BaseResponse<T>)),*/ /*
              completer.complete(BaseResponse.fromJson2<T>(
                  value.data) */ /*默认InternalLinkedHashMap*/ /*),
            })
        */ /*.catchError((error) => {
              completer.complete(null),
              completer.completeError(error),
            })*/ /*
        .whenComplete(() => null);

    return completer.future;
  }
*/
  void addInterceptor(Interceptor interceptor) {
    dio.interceptors.add(interceptor);
  }

  void removeIntercept(Interceptor interceptor) {
    dio.interceptors.remove(interceptor);
  }

  void addHeaders(Map<String, dynamic> map) {
    dio.options.headers.addAll(map);
  }

  void removeHeader(String? key) {
    dio.options.headers.remove(key);
  }

  /// 同一个cancel token 可以用于多个请求，当一个cancel token取消时，所有使用该cancel token的请求都会被取消。
  /// 所以参数可选
  void cancelRequests({CancelToken? token}) {
    token ?? _cancelToken.cancel("cancelled");
  }
}
